<script setup>
import { ref,onMounted } from "vue";
import { addCustomer, getCustomer } from "./indexDB";
import Worker from "./worker2?worker";


/**
 * 提取文件类型
 * 文件名后缀可以随意修改，只有在读取的时候才能获取真实的文件类型，以防有人恶意上传不符合的文件
 * 如果返回数据为null则没有匹配到符合的文件名,可能是漏了，也可能是不存在的文件类型，使用时需核查
 *
 * 微软和WPS生成的的word excel ppt等文件码不一致，且没有区分具体文件后缀，所以在判断相应的码后再解析文件名后缀
 * */
const getFileType = (row) => {
  return new Promise((reslove, reject) => {
    const file = row.file ? row.file : row.raw ? row.raw : row;
    const name = row.name || file.name;
    const reader = new FileReader();
    reader.onload = (evt) => {
      let realMimeType = "";
      const arr = new Uint8Array(reader.result).subarray(0, 4);
      // 将截取的result和magic number比较
      let header = "";
      for (let i = 0; i < arr.length; i++) {
        header += arr[i].toString(16);
      }
      if (header.indexOf("89504e47") === 0) {
        realMimeType = "png";
      } else if (header.indexOf("424d") === 0) {
        realMimeType = "bmp";
      } else if (
        header.indexOf("ffd8ffe0") === 0 ||
        header.indexOf("ffd8ffe1") === 0 ||
        header.indexOf("ffd8ffe2") === 0 ||
        header.indexOf("ffd8ffe3") === 0
      ) {
        realMimeType = "jpeg"; // JPG/JPEG
      } else if (header.indexOf("25504446") === 0) {
        realMimeType = "pdf";
      } else if (header.indexOf("504b34") === 0) {
        realMimeType = name.substr(name.lastIndexOf(".")).substr(1).toLowerCase();
      } else if (header.indexOf("d0cf11e0") === 0 || header.indexOf("3c3f786d") === 0) {
        realMimeType = name.substr(name.lastIndexOf(".")).substr(1).toLowerCase();
      } else if (header.indexOf("47494638") === 0) {
        realMimeType = "gif";
      } else if (header.indexOf("52617221") === 0) {
        realMimeType = "rar";
      } else if (header.indexOf("57617665") === 0 || header.indexOf("52696666") === 0) {
        realMimeType = "wav";
      } else if (header.indexOf("41564920") === 0) {
        realMimeType = "avi";
      } else if (header.indexOf("504b0304") === 0) {
        realMimeType = "zip";
      } else if (header.indexOf("50415220") === 0) {
        realMimeType = "par2";
      } else if (header.indexOf("7b5c727466") === 0) {
        realMimeType = "rtf";
      } else {
        const dotIndex = name.lastIndexOf(".");
        if (dotIndex === -1) return ""; // 如果没有 `.` 返回空字符串
        realMimeType = name.slice(dotIndex + 1); // 获取 `.` 后面的部分
      }

      reslove({ realMimeType, name });
    };
    reader.readAsArrayBuffer(file);
  });
};

//限制并发上传
let ajaxqueue = [];
const maxQueue = 5;
let nowIndex = 0;
let uploadIndex = [];
const upload = (chunkList, fileMd5Value, i, fileName) => {
  let form = new FormData();
  form.append("chunk", chunkList[i]); //切片流
  form.append("chunkIndex", i); //当前是第几片
  form.append("fileHash", fileMd5Value);
  fetch(`http://localhost:5000/upload?fileHash=${fileMd5Value}&chunkIndex=${i}`, {
    method: "POST",
    body: form,
  })
    .then((response) => response.json())
    .then((res) => {
      if (res.code === 200) {
        nowIndex--;
        msg.value = ((1 - uploadIndex.length / chunkList.length) * 100).toFixed(1) + "%";
        if (uploadIndex.length > 0) {
          const t = uploadIndex.shift();
          nowIndex++;
          ajaxqueue.push(upload(chunkList, fileMd5Value, t, fileName));
        }

        if (nowIndex === 0) {
          uploadIndex = [];
          msg.value = "正在合并文件...";
          fetch("http://localhost:5000/merge", {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify({
              fileHash: fileMd5Value,
              fileName,
              totalChunks: chunkList.length,
            }),
          })
            .then((response) => response.json())
            .then((res) => {
              if (res.code === 200) {
                msg.value = "上传成功 -->" + res.data;
              }
            });
        }
      }
    });
};
async function checkAndUploadChunk(fileMd5Value, chunkList, fileName) {
  //检查分片是否已经上传
  let req = await fetch("http://localhost:5000/check", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      fileHash: fileMd5Value,
    }),
  }).then((response) => response.json());

  for (let i = 0; i < chunkList.length; i++) {
    if (req.indexOf(i) != -1) continue;
    uploadIndex.push(i);
  }

  while (nowIndex < maxQueue) {
    const i = uploadIndex.shift();
    nowIndex++;
    ajaxqueue.push(upload(chunkList, fileMd5Value, i, fileName));
  }
}

const msg = ref("");
const handleinput = async (val) => {
  const file = val.target.files[0];

  const { realMimeType, name } = await getFileType(file);
  msg.value = "正在解析文件信息";
  // 创建一个worker对象
  const worker = new Worker();
  // 向子线程发送消息，并传入文件对象和切片大小，开始计算分割切片
  worker.postMessage(file);

  worker.onmessage = (e) => {
    const { fileHash, fileChunks } = e.data;
    checkAndUploadChunk(fileHash, fileChunks, name);
  };
};

</script>

<template>
  <input type="file" name="chunk" @change="handleinput" />
  <p>上传进度：{{ msg }}</p>
</template>

<style scoped></style>
